/*
 * Copyright 2007-2009 Perttu "celeron55" Ahola <celeron55@gmail.com>
 *
 * This file is part of jukumagic.
 *
 * jukumagic is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * jukumagic is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with jukumagic.  If not, see <http://www.gnu.org/licenses/>.
*/

#include <iostream>
#include "common.h"
#include "jumperwire.h"
#include "jukuapp.h"

JumperWire::JumperWire():
m_side(TOP),
m_x1(0),
m_y1(0),
m_x2(0),
m_y2(0),
m_shortstring(wxT("Wundefined"))
//m_last_select_checked_head(-1),
//m_head_selected(-1)
{
	//std::cout<<"JumperWire"<<std::endl;
}

JumperWire::~JumperWire()
{
	//std::cout<<"~JumperWire"<<std::endl;
}

void JumperWire::WriteXML(TiXmlNode* root)
{
    TiXmlElement *element = new TiXmlElement("JumperWire");
    root->LinkEndChild(element);
    if(m_side == TOP) element->SetAttribute("side", "top");
	else if(m_side == BOTTOM) element->SetAttribute("side", "bottom");
    element->SetAttribute("x1", m_x1);
    element->SetAttribute("y1", m_y1);
    element->SetAttribute("x2", m_x2);
    element->SetAttribute("y2", m_y2);
	WriteBaseXML(element);
}

JukuObject* JumperWire::ReadFromXMLElement(TiXmlElement* element)
{
	//std::cout<<"JumperWire::ReadFromXMLElement()"<<std::endl;

    JumperWire *jumperwire = new JumperWire();

	std::string side_s = element->Attribute("side");
	if(side_s == "top") jumperwire->m_side = TOP;
	else if(side_s == "bottom") jumperwire->m_side = BOTTOM;

	element->Attribute("x1", &jumperwire->m_x1);
	element->Attribute("y1", &jumperwire->m_y1);
	element->Attribute("x2", &jumperwire->m_x2);
	element->Attribute("y2", &jumperwire->m_y2);

	jumperwire->ReadBaseXML(element);

	jumperwire->m_shortstring = wxString::Format(wxT("W(%i,%i)->(%i,%i)"), 
			jumperwire->m_x1, jumperwire->m_y1, jumperwire->m_x2, jumperwire->m_y2);
	
    return jumperwire;
}

void JumperWire::Draw(wxDC &dc, wxWindow *window, wxPoint origin)
{
	if(m_side == TOP){
		if(GetSelected()){
			wxPen pen(wxGetApp().m_settings.m_colour_selected,
					wxGetApp().m_settings.m_linewidth_jumper_wire_top);
			dc.SetPen(pen);
		}
		else{
			wxPen pen(wxGetApp().m_settings.m_colour_jumper_wire_top,
					wxGetApp().m_settings.m_linewidth_jumper_wire_top);
			dc.SetPen(pen);
		}
	}
	else if(m_side == BOTTOM){
		if(GetSelected()){
			wxPen pen(wxGetApp().m_settings.m_colour_selected,
					wxGetApp().m_settings.m_linewidth_jumper_wire_bottom);
			dc.SetPen(pen);
		}
		else{
			wxPen pen(wxGetApp().m_settings.m_colour_jumper_wire_bottom,
					wxGetApp().m_settings.m_linewidth_jumper_wire_bottom);
			dc.SetPen(pen);
		}
	}

	dc.DrawLine(m_x1 + origin.x, m_y1 + origin.y, m_x2 + origin.x, m_y2 + origin.y);
	
	//if(m_head_selected != -1){
	if(GetSelected()){
		wxPen pen(wxGetApp().m_settings.m_colour_jumper_wire_selected_head,
				wxGetApp().m_settings.m_linewidth_jumper_wire_selected_head);
		dc.SetPen(pen);
		wxBrush brush(*wxBLACK, wxTRANSPARENT);
		dc.SetBrush(brush);
		//if(m_head_selected == 1){
			dc.DrawCircle(m_x1 + origin.x, m_y1 + origin.y, wxGetApp().m_settings.m_radius_jumper_wire_selected_head);
		//}
		//else if(m_head_selected == 2){
			dc.DrawCircle(m_x2 + origin.x, m_y2 + origin.y, wxGetApp().m_settings.m_radius_jumper_wire_selected_head);
		//}
	}
}

BoardRect JumperWire::GetDrawArea()
{
	int x1, y1, x2, y2;
	if(m_x1 > m_x2){
		x1 = m_x2;
		x2 = m_x1;
	}
	else{
		x1 = m_x1;
		x2 = m_x2;
	}
	if(m_y1 > m_y2){
		y1 = m_y2;
		y2 = m_y1;
	}
	else{
		y1 = m_y1;
		y2 = m_y2;
	}
	//if(m_head_selected!=-1){
		return BoardRect(x1-wxGetApp().m_settings.m_linewidth_jumper_wire_selected_head/2
				-wxGetApp().m_settings.m_radius_jumper_wire_selected_head,
				y1-wxGetApp().m_settings.m_linewidth_jumper_wire_selected_head/2
				-wxGetApp().m_settings.m_radius_jumper_wire_selected_head,
				x2-x1+wxGetApp().m_settings.m_linewidth_jumper_wire_selected_head
				+wxGetApp().m_settings.m_radius_jumper_wire_selected_head*2,
				y2-y1+wxGetApp().m_settings.m_linewidth_jumper_wire_selected_head
				+wxGetApp().m_settings.m_radius_jumper_wire_selected_head*2);
	/*}
	else{
		if(m_side==TOP){
			return BoardRect(x1-wxGetApp().m_settings.m_linewidth_jumper_wire_top/2,
					y1-wxGetApp().m_settings.m_linewidth_jumper_wire_top/2,
					x2-x1+wxGetApp().m_settings.m_linewidth_jumper_wire_top,
					y2-y1+wxGetApp().m_settings.m_linewidth_jumper_wire_top);
		}
		else{
			return BoardRect(x1-wxGetApp().m_settings.m_linewidth_jumper_wire_bottom/2,
					y1-wxGetApp().m_settings.m_linewidth_jumper_wire_bottom/2,
					x2-x1+wxGetApp().m_settings.m_linewidth_jumper_wire_bottom,
					y2-y1+wxGetApp().m_settings.m_linewidth_jumper_wire_bottom);
		}
	}*/
}

BoardPoint JumperWire::GetBoardPos()
{
	return BoardPoint(0,0);
}

void JumperWire::Move(int dx, int dy)
{
	m_x1 += dx;
	m_y1 += dy;
	m_x2 += dx;
	m_y2 += dy;
	ReportChange(OBJECT_CHANGE_CONTENTS);
}

int JumperWire::GetSide()
{
	return m_side;
}

void JumperWire::SetSide(BoardSide newside)
{
	m_side = newside;
	ReportChange(OBJECT_CHANGE_CONTENTS);
}

bool JumperWire::IsSelectedInPoint(int x, int y)
{
	if(abs(x-m_x1) < 50 && abs(y-m_y1) < 50){
		//m_last_select_checked_head = 1;
		return true;
	}
	if(abs(x-m_x2) < 50 && abs(y-m_y2) < 50){
		//m_last_select_checked_head = 2;
		return true;
	}

	//m_last_select_checked_head = -1;
	
	if(m_x1 != m_x2 && m_y1 != m_y2) return false;

	if(m_x1 == m_x2){
		int y1, y2;
		if(m_y1 > m_y2){
			y1 = m_y2;
			y2 = m_y1;
		}
		else{
			y1 = m_y1;
			y2 = m_y2;
		}
		if(abs(x-m_x1) < 50 && y > y1-50 && y < y2+50) return true;
	}
	if(m_y1 == m_y2){
		int x1,x2;
		if(m_x1 > m_x2){
			x1 = m_x2;
			x2 = m_x1;
		}
		else{
			x1 = m_x1;
			x2 = m_x2;
		}
		if(x > x1-50 && x < x2+50 && abs(y-m_y1) < 50) return true;
	}

	return false;
}

bool JumperWire::IsSelectedInArea(int sx1, int sy1, int sx2, int sy2, bool touch_is_enough)
{
	BoardRect sr(sx1, sy1, sx2-sx1, sy2-sy1);
	BoardRect wr;

	wr = BoardRect(m_x1-50, m_y1-50, 100, 100);
	if(touch_is_enough){
		if(sr.Collides(wr)) return true;
	}
	else{
		if(sr.Contains(wr)) return true;
	}

	wr = BoardRect(m_x2-50, m_y2-50, 100, 100);
	if(touch_is_enough){
		if(sr.Collides(wr)) return true;
	}
	else{
		if(sr.Contains(wr)) return true;
	}

	if(touch_is_enough && m_x1 != m_x2 && m_y1 != m_y2 && !GetSelected()){
		return false;
	}

	int wx1, wy1, wx2, wy2;
	if(m_x1 > m_x2){
		wx1 = m_x2;
		wx2 = m_x1;
	}
	else{
		wx1 = m_x1;
		wx2 = m_x2;
	}
	if(m_y1 > m_y2){
		wy1 = m_y2;
		wy2 = m_y1;
	}
	else{
		wy1 = m_y1;
		wy2 = m_y2;
	}
	if(touch_is_enough){
		wx1 -= 50;
		wy1 -= 50;
		wx2 += 50;
		wy2 += 50;
	}

	wr = BoardRect(wx1, wy1, wx2-wx1, wy2-wy1);

	if(touch_is_enough){
		if(sr.Collides(wr)) return true;
	}
	else{
		if(sr.Contains(wr)) return true;
	}

	return false;
}

void JumperWire::SetSelected(bool selected)
{
	//if(!selected) SelectHead(-1);
	JukuObject::SetSelected(selected);
}
	
void JumperWire::Rotate(TurnDirection dir, BoardPoint origin)
{
	int ox1 = m_x1 - origin.m_x;
	int oy1 = m_y1 - origin.m_y;
	int ox2 = m_x2 - origin.m_x;
	int oy2 = m_y2 - origin.m_y;
	int nox1, noy1, nox2, noy2;
	if(dir==CCW){
		nox1 = oy1;
		nox2 = oy2;
		noy1 = -ox1;
		noy2 = -ox2;
	}
	else{ //CW
		nox1 = -oy1;
		nox2 = -oy2;
		noy1 = ox1;
		noy2 = ox2;
	}
	m_x1 = origin.m_x + nox1;
	m_y1 = origin.m_y + noy1;
	m_x2 = origin.m_x + nox2;
	m_y2 = origin.m_y + noy2;
	m_shortstring = wxString::Format(wxT("W(%i,%i)->(%i,%i)"), 
			m_x1, m_y1, m_x2, m_y2);
	ReportChange(OBJECT_CHANGE_CONTENTS);
}

/*void JumperWire::Rotate180()
{
	int tx = m_x1;
	m_x1 = m_x2;
	m_x2 = tx;
}*/

BoardRect JumperWire::GetPinExtents()
{
	int wx1, wy1, wx2, wy2;
	if(m_x1 > m_x2){
		wx1 = m_x2;
		wx2 = m_x1;
	}
	else{
		wx1 = m_x1;
		wx2 = m_x2;
	}
	if(m_y1 > m_y2){
		wy1 = m_y2;
		wy2 = m_y1;
	}
	else{
		wy1 = m_y1;
		wy2 = m_y2;
	}
	return BoardRect(wx1, wy1, wx2-wx1, wy2-wy1);
}

int JumperWire::GetHeadAtPoint(int x, int y)
{
	//std::cout<<"JumperWire::GetHeadAtPoint(x="<<x<<", y="<<y<<")"<<std::endl;
	//std::cout<<"head1:("<<m_x1<<","<<m_y1<<") head2:("<<m_x2<<","<<m_y2<<")"<<std::endl;
	if(abs(x-m_x1) < 50 && abs(y-m_y1) < 50){
		return 1;
	}
	if(abs(x-m_x2) < 50 && abs(y-m_y2) < 50){
		return 2;
	}
	return -1;
}
/*
void JumperWire::SelectHead(int head)
{
	m_head_selected = head;
}
*/
BoardPoint JumperWire::GetHeadPoint(int head)
{
	if(head==1){
		return BoardPoint(m_x1, m_y1);
	}
	else if(head==2){
		return BoardPoint(m_x2, m_y2);
	}
	return BoardPoint();
}

void JumperWire::SetHeadPoint(int head, BoardPoint p)
{
	if(head==1){
		m_x1 = p.m_x;
		m_y1 = p.m_y;
	}
	else if(head==2){
		m_x2 = p.m_x;
		m_y2 = p.m_y;
	}
	m_shortstring = wxString::Format(wxT("W(%i,%i)->(%i,%i)"), 
			m_x1, m_y1, m_x2, m_y2);
	ReportChange(OBJECT_CHANGE_CONTENTS);
}

